public class Grid
{
	private int[][] grid = new int[P4.HEIGHT][P4.WIDTH];
	private int joueur_courant;
	private int cases_vides;

	private int[][] alignements = new int[2][4];

	// decrit l'etat de la situation pour tous les alignements possibles
	private int[][] h=new int[6][4]; //horizontal
	private int[][] v=new int[3][7]; //vertical
	private int[][] dd=new int[3][4]; //diagonal "vers la droite" (/)
	private int[][] dg=new int[3][4]; //diagonal "vers la gauche" (\)


	public static final int _0_0 = 0;
	public static final int _0_1 = 1;
	public static final int _0_2 = 2;
	public static final int _0_3 = 3;
	public static final int _0_4 = 4;
	public static final int _1_0 = 5;
	public static final int _1_1 = 6;
	public static final int _1_2 = 7;
	public static final int _1_3 = 8;
	public static final int _2_0 = 9;
	public static final int _2_1 = 10;
	public static final int _2_2 = 11;
	public static final int _3_0 = 12;
	public static final int _3_1 = 13;
	public static final int _4_0 = 14;

	public static final int PLAYER1=P4.PLAYER1;
	public static final int PLAYER2=P4.PLAYER2;


	public static final int PB = 42;

	public Grid()
	{
		for(int i=0 ; i<P4.HEIGHT ; i++)
			for(int j=0 ; j<P4.WIDTH ; j++)
				grid[i][j]=P4.EMPTY;

		joueur_courant = P4.PLAYER1;
		cases_vides = P4.HEIGHT*P4.WIDTH;

		for(int i=0 ; i<2 ; i++)
			for(int j=0 ; j<4 ; j++)
				alignements[i][j]=0;

		for(int i=0 ; i<6 ; i++)
			for(int j=0 ; j<4 ; j++)
				h[i][j]=_0_0;

		for(int i=0 ; i<3 ; i++)
			for(int j=0 ; j<7 ; j++)
				v[i][j]=_0_0;

		for(int i=0 ; i<3 ; i++)
			for(int j=0 ; j<4 ; j++)
				dd[i][j]=_0_0;

		for(int i=0 ; i<3 ; i++)
			for(int j=0 ; j<4 ; j++)
				dg[i][j]=_0_0;
	}

	public Grid(Grid g)
	{
		for(int i=0 ; i<P4.HEIGHT ; i++)
			for(int j=0 ; j<P4.WIDTH ; j++)
				grid[i][j]=g.grid[i][j];

		joueur_courant = g.joueur_courant;
		cases_vides = g.cases_vides;

		for(int i=0 ; i<2 ; i++)
			for(int j=0 ; j<4 ; j++)
				alignements[i][j]=g.alignements[i][j];

		for(int i=0 ; i<6 ; i++)
			for(int j=0 ; j<4 ; j++)
				h[i][j]=g.h[i][j];

		for(int i=0 ; i<3 ; i++)
			for(int j=0 ; j<7 ; j++)
				v[i][j]=g.v[i][j];

		for(int i=0 ; i<3 ; i++)
			for(int j=0 ; j<4 ; j++)
				dd[i][j]=g.dd[i][j];

		for(int i=0 ; i<3 ; i++)
			for(int j=0 ; j<4 ; j++)
				dg[i][j]=g.dg[i][j];
	}

	public boolean full()
	{
		return cases_vides==0;
	}

	public int put(int y)
	{
		if(grid[5][y]!=P4.EMPTY)
			return P4.COLONNE_NON_VALIDE;

		int x=0;
		while(x<6)
		{
			if(grid[x][y]==P4.EMPTY){
				/*if(joueur_courant==PLAYER1)
	    System.out.print("J1");
	    else
	    System.out.print("J2");
	    System.out.println(" put "+x+","+y);*/
	    grid[x][y]=joueur_courant;
	    cases_vides--;

	    //alignements horizontaux
	    for(int i=Math.max(0,y-3) ; i<=Math.min(3,y) ; i++)
	    {
	    	h[x][i]=update(h[x][i]);
	    }
	    //alignements verticaux
	    for(int i=Math.max(0,x-3) ; i<=Math.min(2,x) ; i++)
	    {
	    	v[i][y]=update(v[i][y]);
	    }
	    //diagonales
	    for(int i=0 ; i<=3 ; i++)
	    {	// droite
	    	if(x-i>=0&&y-i>=0&&x-i<3&&y-i<4)
	    		dd[x-i][y-i]=update(dd[x-i][y-i]);
	    	// gauche
	    	if(x-i>=0&&y-3+i<4&&x-i<3&&y-3+i>=0)
	    		dg[x-i][y-3+i]=update(dg[x-i][y-3+i]);
	    }
	    //System.out.println(alignements[0][0]+" "+alignements[0][1]+" "+alignements[0][2]+" "+alignements[1][0]+" "+alignements[1][1]+" "+alignements[1][2]);
	    return x;
			}
			x++;
		}
		return P4.COLONNE_NON_VALIDE;
	}

	public int remove(int y)
	{
		if(grid[0][y]==P4.EMPTY)
			return P4.COLONNE_NON_VALIDE;
		int x=P4.HEIGHT-1;
		while(x>=0)
		{
			if(grid[x][y]!=P4.EMPTY){
				if(grid[x][y]!=joueur_courant)
					System.out.println("pb");
				/*if(joueur_courant==PLAYER1)
	    System.out.print("J1");
	    else
	    System.out.print("J2");
	    System.out.println(" remove "+x+","+y);*/
				grid[x][y]=P4.EMPTY;
				cases_vides++;

				//alignements horizontaux
				for(int i=Math.max(0,y-3) ; i<=Math.min(3,y) ; i++)
				{
					h[x][i]=un_update(h[x][i]);
				}
				//alignements verticaux
				for(int i=Math.max(0,x-3) ; i<=Math.min(2,x) ; i++)
				{
					v[i][y]=un_update(v[i][y]);
				}
				//diagonales
				for(int i=0 ; i<=3 ; i++)
				{	// droite
					if(x-i>=0&&y-i>=0&&x-i<3&&y-i<4)
						dd[x-i][y-i]=un_update(dd[x-i][y-i]);
					// gauche
					if(x-i>=0&&y-3+i<4&&x-i<3&&y-3+i>=0)
						dg[x-i][y-3+i]=un_update(dg[x-i][y-3+i]);
				}

				return x;
			}
			x--;
		}
		return P4.COLONNE_NON_VALIDE;
	}

	public int update(int prec)
	{
		int val=PB;
		if(joueur_courant==P4.PLAYER1)
		{
			switch(prec)
			{
			case _0_0:
				val=_1_0;
				alignements[PLAYER1][0]++;
				break;
			case _0_1:
				val=_1_1;
				alignements[PLAYER2][0]--;
				break;
			case _0_2:
				val=_1_2;
				alignements[PLAYER2][1]--;
				break;
			case _0_3:
				val=_1_3;
				alignements[PLAYER2][2]--;
				break;
			case _1_0:
				val=_2_0;
				alignements[PLAYER1][0]--;
				alignements[PLAYER1][1]++;
				break;
			case _1_1:
				val=_2_1;
				break;
			case _1_2:
				val=_2_2;
				break;
			case _2_0:
				val=_3_0;
				alignements[PLAYER1][1]--;
				alignements[PLAYER1][2]++;
				break;
			case _2_1:
				val=_3_1;
				break;
			case _3_0:
				val=_4_0;
				alignements[PLAYER1][2]--;
				alignements[PLAYER1][3]++;
				break;
			}
		}
		else
		{
			switch(prec)
			{
			case _0_0:
				val=_0_1;
				alignements[PLAYER2][0]++;
				break;
			case _0_1:
				val=_0_2;
				alignements[PLAYER2][0]--;
				alignements[PLAYER2][1]++;
				break;
			case _0_2:
				val=_0_3;
				alignements[PLAYER2][1]--;
				alignements[PLAYER2][2]++;
				break;
			case _0_3:
				val=_0_4;
				alignements[PLAYER2][2]--;
				alignements[PLAYER2][3]++;
				break;
			case _1_0:
				val=_1_1;
				alignements[PLAYER1][0]--;
				break;
			case _1_1:
				val=_1_2;
				break;
			case _1_2:
				val=_1_3;
				break;
			case _2_0:
				val=_2_1;
				alignements[PLAYER1][1]--;
				break;
			case _2_1:
				val=_2_2;
				break;
			case _3_0:
				val=_3_1;
				alignements[PLAYER1][2]--;
				break;
			}
		}
		return val;
	}

	public int un_update(int prec)
	{
		int val=PB;
		if(joueur_courant==P4.PLAYER1)
		{
			switch(prec)
			{
			case _1_0:
				val=_0_0;
				alignements[PLAYER1][0]--;
				break;
			case _1_1:
				val=_0_1;
				alignements[PLAYER2][0]++;
				break;
			case _1_2:
				val=_0_2;
				alignements[PLAYER2][1]++;
				break;
			case _1_3:
				val=_0_3;
				alignements[PLAYER2][2]++;
				break;
			case _2_0:
				val=_1_0;
				alignements[PLAYER1][1]--;
				alignements[PLAYER1][0]++;
				break;
			case _2_1:
				val=_1_1;
				break;
			case _2_2:
				val=_1_2;
				break;
			case _3_0:
				val=_2_0;
				alignements[PLAYER1][2]--;
				alignements[PLAYER1][1]++;
				break;
			case _3_1:
				val=_2_1;
				break;
			case _4_0:
				val=_3_0;
				alignements[PLAYER1][3]--;
				alignements[PLAYER1][2]++;
				break;
			}
		}
		else
		{
			switch(prec)
			{
			case _0_1:
				val=_0_0;
				alignements[PLAYER2][0]--;
				break;
			case _0_2:
				val=_0_1;
				alignements[PLAYER2][1]--;
				alignements[PLAYER2][0]++;
				break;
			case _0_3:
				val=_0_2;
				alignements[PLAYER2][2]--;
				alignements[PLAYER2][1]++;
				break;
			case _0_4:
				val=_0_3;
				alignements[PLAYER2][3]--;
				alignements[PLAYER2][2]++;
				break;
			case _1_1:
				val=_1_0;
				alignements[PLAYER1][0]++;
				break;
			case _1_2:
				val=_1_1;
				break;
			case _1_3:
				val=_1_2;
				break;
			case _2_1:
				val=_2_0;
				alignements[PLAYER1][1]++;
				break;
			case _2_2:
				val=_2_1;
				break;
			case _3_1:
				val=_3_0;
				alignements[PLAYER1][2]++;
				break;
			}
		}
		return val;
	}

	public boolean win(int player)
	{
		if(alignements[player][3]!=0)
			return true;
		return false;
	}

	public boolean win()
	{
		return win(joueur_courant);
	}

	public boolean won()
	{
		if(joueur_courant==PLAYER1)
			return win(PLAYER2);
		else
			return win(PLAYER1);
	}

	public int evaluation()
	{
		int res=alignements[0][0]+100*alignements[0][1]+10000*alignements[0][2]-alignements[1][0]-100*alignements[1][1]-10000*alignements[1][2];
		if(joueur_courant==PLAYER1)
			return res;
		return -res;
	}

	public void switchJoueur()
	{
		if(joueur_courant==PLAYER1)
		{
			joueur_courant=PLAYER2;
		}
		else
		{
			joueur_courant=PLAYER1;
		}
	}

	public int getGrid(int y, int x)
	{
		return grid[y][x];
	}
	
	public void setGrid(int y, int x, int val)
	{
		if(x >= 0 && x < P4.WIDTH && y >= 0 && y < P4.HEIGHT)
			grid[y][x] = val;
		else
			System.out.println("setGrid out of range");
	}

	public void setJoueur(int j){joueur_courant=j;}
	public int getJoueur(){return joueur_courant;}
}
